package com.iwe3.protal.handler;

import cn.hutool.json.JSONUtil;
import com.iwe3.protal.Enum.SystemEnum;
import com.iwe3.protal.common.R;
import com.iwe3.protal.util.TokenUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.TimeUnit;

@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Value("${token.signature}")
    private String signature;

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;
    /**
     * 执行：请求达到 Controller接口之前
     * @param request
     * @param response
     * @param handler
     * @return true 代表请求 -> Controller的接口上去
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //从请求头中，获得token令牌
        String authentication = request.getHeader("authentication");
        if(!StringUtils.hasLength(authentication)){
            //去登录
            write(response);
            return false;
        }
        //校验Token是否合法
        String token = authentication.replace("Bearer ", "");
        boolean verify = TokenUtil.verify(token, signature);
        if(!verify){
            write(response);
            return false;
        }
        //校验Token是否劫持
        String ip = (String) TokenUtil.parsePayLoad(token, "ip");
        String clientIp = getClientIp(request);
        if(!ip.equals(clientIp)){
            write(response);
            return false;
        }
        //判断Redis中是否有Token[模拟：Tomcat -> Session的处理方案]
        if(!redisTemplate.hasKey(token)){
            write(response);
            return false;
        }
        //重新续期30分钟
        redisTemplate.expire(token,30, TimeUnit.MINUTES);
        return true;//TOKEN校验合法
    }

    private String getClientIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        // 如果通过了多个代理，那么X-Forwarded-For的值并不止一个，
        // 而是一串IP值，需要进行处理。
        if (ip != null && ip.contains(",")) {
            ip = ip.split(",")[0];
        }
        return ip;
    }

    private void write(HttpServletResponse response){
        response.setContentType("application/json;charset=utf-8");
        try {
            PrintWriter out = response.getWriter();
            R r = R.fail(SystemEnum.RELOGIN);
            String s = JSONUtil.toJsonStr(r);
            out.write(s);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}